package tracing;
// Tracing.java
//
// Informatics 102 Spring 2012
// In-class example: a global program-tracing aspect
//
// One purpose of an aspect is to represent a crosscutting feature.  A simple
// example of a crosscutting feature is one that writes a message to
// System.out each time a method is entered and another each time a method is
// exited.  Aspects allow you to write a combination of three things that you
// can use to implement a crosscutting feature:
//
//  * Pointcuts, which define a set of join points (i.e., points or regions
//    before which, after which, or in place of which AspectJ can weave code)
//
//  * Advice, which is the code that should be woven in at these points
//
//  * Inter-type declarations, which are new fields, new methods, and new
//    inheritance relationships (extends or implements) to be added into
//    existing classes
//
// Additionally, aspects can contain additional code that is not woven into
// any other places at all, but is instead local to the aspect itself; this
// allows you to write code that supports only the advice that you write
// within an aspect.
//
// Our tracing aspect aims to add a global tracing facility into an existing
// program.  On entry to every method, a message such as this is printed:
//
//    Entering void Y.uno()
//
// Upon exit of every method, a message such as this is printed:
//
//    Exiting void Y.uno()
//
// Indention is used to show call depth, so that a sequence of these messages
// might appear like this:
//
//    Entering void Y.dos()
//      Entering void Y.uno()
//      Exiting void Y.uno()
//    Exiting void Y.dos()
//
// To write this aspect, we need to consider how to handle three problems:
//
//   * How do we specify where code that prints the entry and exit messages
//     should be woven?  This is the job of a pointcut, so we'll need to
//     write an appropriate pointcut.
//
//   * What code should be woven in so that the right messages will be printed?
//
//   * How should we handle indention, which can't be the responsibility of
//     each individual class, since it is a concept that is global to the
//     entire program -- or, rather, local to this aspect of the program?
//
// Comments throughout the aspect answer these questions.



// Declaring an aspect is much like declaring a class in Java, with the
// word "aspect" replacing the word "class."  Since we'd like our aspect
// to be available throughout our program, we'll declare it to be public.

public aspect Tracing
{
	// This is a field of the Tracing aspect, not of any particular class.
	// Aspects, for the most part, can be thought of as singleton objects,
	// meaning that there is one Tracing "object" for the entire program
	// and, thus, one depth field for the entire program.  (There are ways
	// to control this if you need multiple instances of an aspect, but we
	// won't ever need to do it for our work in this course.)
	//
	// We will increment the depth every time a call is made to a method
	// and decrement it every time a method returns, so a good initial
	// value is -1.  That way, when we increment the field before printing
	// the first entry message, its value will become 0.
	private int depth = -1;


	// A pointcut specifies a set of join points.  In other words, it tells
	// AspectJ where to weave code into existing classes (or other aspects).
	// In this case, we want to weave code to print a message at the
	// beginning and end of the execution of every method and every constructor
	// in the program.  (The execution of a method refers to its entire body.)
	// The pointcut is built out of primitive pointcuts, which are the building
	// blocks provided by the AspectJ language to specify pointcuts:
	//
	//     execution(* *.*(..))
	//         This pointcut selects the execution of every method, regardless
	//         of its return type (that's what the first '*' signifies),
	//         regardless of its class and name (that's what the '*.*'
	//         signifies), and regardless of the number or types of parameters
	//         (that's what the ".." signifies).  The execution of a method
	//         encompasses, essentially, the code within the curly braces that
	//         surround the method's body.
	//
	//     execution(*.new(..))
	//         This pointcut selects the execution of every constructor,
	//         regardless of its type (which is what the '*' means) and
	//         regardless of its parameter types (hence the ".." again).
	//         Constructors have no return type, which is why the first
	//         '*' wildcard is "missing" from what you saw in the previous
	//         primitive pointcut.  The reason we need this is because
	//         constructors are not considered to be methods, so we need
	//         to match them differently.
	//
	// We could put these two pointcuts together like this:
	//
	//     pointcut allMethodBodies():
	//         execution(* *.*(..)) || execution(*.new(..));
	//
	// Each of the primitive "execution" pointcuts signifies a set of join
	// points.  The || operator signifies a union operation, so the
	// allMethodBodies() pointcut is the union of the set of the bodies of
	// all methods and the set of all the bodies of all constructors.
	//
	// (Another way to look at it is that a join point is selected by this
	// pointcut if it is either a call to a method *or* a call to a
	// constructor.  Either way of thinking about it yields the same set
	// of join points.)
	//
	// However, we'd have a very serious problem if we left our pointcut as
	// defined above.  We're going to weave advice before and after each
	// join point selected by this pointcut (i.e., at the beginning and end of
	// the execution of every method and every constructor).  The advice we
	// write is going to call a method defined in this aspect that prints the
	// indenting spaces.  Now, if we select *every* method, we'll be selecting
	// not only the methods in every class in the program, but we'll also be
	// selecting any methods in this aspect.  So, whenever a method in some
	// class begins executing, it will first execute our advice, which will
	// call our printIndent() method, which will execute our advice, which
	// will then call our printIndent() method, ... BOOM!  Infinite recursion.
	//
	// To avoid this problem, we take the Tracing aspect out of the pointcut.
	//
	//     within(Tracing)
	//         This pointcut selects every join point within the Tracing aspect.
	//
	//     !within(Tracing)
	//         This pointcut selects every join point *not* within the Tracing
	//         aspect.
	//
	// Finally, using the set intersection (&&) operator, we put together 
	// our final pointcut, selecting the execution of every method and every
	// constructor *except* those defined within the Tracing aspect.

	pointcut allMethodBodies():
		(execution(* *.*(..)) || execution(*.new(..))) && !within(Tracing) && !within(Y);


	// Now we need to write our advice.  Before the execution of each method
	// and constructor selected by our pointcut, we want to increment the
	// depth, indent if necessary, then print our entry message.  "Before
	// advice" is advice that is woven before each join point selected by
	// some pointcut.  Here, we're saying "Add this code before the execution
	// of all methods."
	//
	// Note that "thisJoinPoint" refers to information about the current join
	// point (the one that this advice is advising).  In our case, it tells us
	// about the method whose body we're in.  By printing its signature, we can
	// see what method it is.

	before():
		allMethodBodies()
	{
		depth++;
		printIndent();
		System.out.println("Entering " + thisJoinPoint.getSignature());
	}
	

	// "After advice" is advice that is woven after each join point selected
	// by some pointcut.  This advice adds code after the execution of all
	// methods.  There are two ways to leave a join point: normally (i.e.,
	// because the code finished) and because of an exception, and we can
	// distinguish between these cases in AspectJ.  Here, we separate the
	// case of a method returning from the case of a method throwing an
	// exception.  "after() returning" weaves advice at all of the exit
	// points from a method at which the method is returning normally, while
	// "after() throwing (...)" weaves advice at all of the exit points
	// from a method at which the method has thrown a particular kind of
	// exception.  In this case, I'm interesting in all kinds of exceptions,
	// so I've said "after() throwing (Throwable t)", because anything that
	// can be thrown implements the Throwable interface; you can be more
	// specific if you prefer.
	
	after() returning:
		allMethodBodies()
	{
		printIndent();
		System.out.println("Exiting " + thisJoinPoint.getSignature());
		depth--;
	}


	after() throwing (Throwable t): allMethodBodies()
	{
		printIndent();

		System.out.println(
			"Exiting " + thisJoinPoint.getSignature()
			+ " (" + t.getClass().getName() + " thrown)");

		depth--;
	}
	

	// This method is used only within our aspect, so we mark it private,
	// just like a private method in a class.  It prints two spaces for
	// each level of depth.
	private void printIndent()
	{
		for (int i = 0; i < depth; i++)
		{
			System.out.print("  ");
		}
	}
}
